home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.qualcomm.com
/
2014.06.ftp.qualcomm.com.tar
/
ftp.qualcomm.com
/
eudora
/
developers
/
emsapi
/
carbon_emsapi.sit.hqx
/
Macintosh API Support
/
mimetype.c
< prev
next >
Wrap
Text File
|
2001-03-08
|
11KB
|
371 lines
/* ======================================================================
Functions to manage MIME type data structures for use
with Eudora translation API on the Mac.
Filename: mimetype.c
Last Edited: March 7, 1997
Authors: Laurence Lundblade, Myra Callen, Bob Fronabarger
Copyright: 1995, 1996 QUALCOMM Inc.
Technical support: <emsapi-info@qualcomm.com>
*/
#include <string.h>
#include "emsapi-mac.h"
#include "mimetype.h"
#include "copycat.h"
#include "rfc822.h"
void FreeParamType(emsMIMEparamH paramH);
/* =========================================================================
* Create a data structure to hold a MIME type. Add parameters later on with
* calls to AddMimeParameter.
*
* Args: mimeType -- the main MIME type: e.g., text, application, image
* subType -- the sub type: e.g., plain, octet-stream, jpeg
* mimeV -- the MIME version number
*
* Returns: Handle for the emsMIMEtype data structure
*/
emsMIMEtypeH MakeMimeType(const StringPtr mimeType,
const StringPtr subType, const StringPtr mimeV)
{
emsMIMEtype mType, **mTypeHandle = nil;
if (mimeType && subType) {
mType.size = sizeof(emsMIMEtype);
BlockMoveData(mimeType, mType.mimeType, mimeType[0] + 1);
BlockMoveData(subType, mType.subType, subType[0] + 1);
if (mimeV != nil)
BlockMoveData(mimeV, mType.mimeVersion, mimeV[0] + 1);
else
BlockMoveData("\p1.0", mType.mimeVersion, 4);
mType.params = nil;
mType.contentDisp[0] = '\0';
mType.contentParams = nil;
}
PtrToHand(&mType, (Handle*) &mTypeHandle, sizeof(emsMIMEtype));
return mTypeHandle;
}
/* =========================================================================
* Create an emsMIMEtype structure to hold MIME information. Structure is
* initialized to values provided in RFC822 content-type header line. This
* includes all parameter name-value pairs.
*
* NOTE: The user of this function is responsible for calling
* FreeMimeType() on returned structure.
*
* Args: content_type [IN] The RFC822 content-type string to parse
*
* Returns: Pointer to the created emsMIMEtype structure, nil if error.
*/
emsMIMEtypeH ParseMakeMimeType(const char *content_type)
{
char *cp;
char *mime_type, *mime_subtype, *name, *value;
emsMIMEtypeH mimeHdl;
if (strnicmp(content_type, kContentTypeHdrCStr, kContentTypeHdrLen) != 0)
return nil;
cp = (char*) content_type + kContentTypeHdrLen;
mime_subtype = nil;
mime_type = RFC822_ExtractToken(&cp);
if ((strlen(mime_type) > 0) && ((*cp++) == '/')) {
mime_subtype = RFC822_ExtractToken((char**) &cp);
if (strlen(mime_subtype) > 0) { // We have a type/subtype
c2pstrcpy((StringPtr)mime_type,mime_type);
c2pstrcpy((StringPtr)mime_subtype,mime_subtype);
mimeHdl = MakeMimeType((StringPtr)mime_type, (StringPtr)mime_subtype, nil);
DisposePtr(mime_type);
DisposePtr(mime_subtype);
if (mimeHdl) {
name = value = nil;
do {
if ((*cp++) != ';') // Skip semi-colon
break;
if (!(name = RFC822_ExtractToken(&cp)))
break;
if ((*cp++) != '=') // Skip equals
break;
if (!(value = RFC822_ExtractToken(&cp)))
break;
if ((strlen(name) > 0) && (strlen(value) > 0))
{
c2pstrcpy((StringPtr)name,name);
c2pstrcpy((StringPtr)value,value);
AddMimeParameter(mimeHdl,(StringPtr) name,(StringPtr) value);
}
DisposePtr(name);
DisposePtr(value);
name = value = nil;
} while (*cp);
if (name)
DisposePtr(name);
if (value)
DisposePtr(value);
return mimeHdl;
}
}
}
if (mime_type)
DisposePtr((Ptr) mime_type);
if (mime_subtype)
DisposePtr((Ptr) mime_subtype);
return nil;
}
/* =========================================================================
* Free a data structure holding a MIME type
*
* Args: Handle for the emsMIMEtype to be freed
*/
void FreeMimeType(emsMIMEtypeH mimeH)
{
if (mimeH != nil) {
FreeParamType((**mimeH).params);
FreeParamType((**mimeH).contentParams);
DisposeHandle((Handle) mimeH);
}
}
/* =========================================================================
* Convert a MIME type structure to a string in the format it is usually
* presented in in a Content-Type: header. This includes quoting the parameter
* values and so on.
*
* Args: Handle for the emsMIMEtype
*
* Returns: Handle to a block of ASCII formatted for use in a Content-Type: header
* (note: it is not a Pascal string, nor a C string)
*/
Handle StringMimeType(emsMIMEtypeH mimeH)
{
const char *kPrefixStr = "Content-Type: ";
const char *kParamSepStr = ";\r\n ";
const char *kTypeSubtypeSepStr = "/";
const char *kAttValueSepStr = "=";
emsMIMEtypeP mimeP;
emsMIMEparamH paramHdl;
unsigned short n, hLen;
Handle hStr, h;
char *cp;
Str255 theStr;
if (mimeH == nil)
return nil;
if (StrLength((**mimeH).mimeType) == 0 || StrLength((**mimeH).subType) == 0)
return nil; // Both TYPE and SUBTYPE are required by RFC822
HLock((Handle) mimeH);
mimeP = *mimeH;
hLen = strlen(kPrefixStr); // Calculate the length of the header string
hLen += RFC822_QuotedStrLen(mimeP->mimeType);
hLen += strlen(kTypeSubtypeSepStr);
hLen += RFC822_QuotedStrLen(mimeP->subType);
paramHdl = mimeP->params;
while (paramHdl) {
hLen += strlen(kParamSepStr);
hLen += RFC822_QuotedStrLen((**paramHdl).name);
hLen += strlen(kAttValueSepStr);
hStr = (**paramHdl).value; // make string from value handle
n = GetHandleSize(hStr);
BlockMoveData(*hStr, theStr + 1, n);
theStr[0] = n;
hLen += RFC822_QuotedStrLen(theStr);
paramHdl = (**paramHdl).next;
}
hStr = NewHandle(hLen + 1); // Allocate space for the header line
if (!hStr)
goto Exit;
HLock(hStr); // Build the header line
cp = *hStr;
cp = strchr(strcpy(cp, kPrefixStr), '\0');
cp = RFC822_QuoteStrCpy(cp, mimeP->mimeType);
cp = strchr(strcpy(cp, kTypeSubtypeSepStr), '\0');
cp = RFC822_QuoteStrCpy(cp, mimeP->subType);
paramHdl = mimeP->params;
while (paramHdl) {
cp = strchr(strcpy(cp, kParamSepStr), '\0');
cp = RFC822_QuoteStrCpy(cp, (**paramHdl).name);
cp = strchr(strcpy(cp, kAttValueSepStr), '\0');
h = (**paramHdl).value;
n = GetHandleSize(h);
BlockMoveData(*h, theStr + 1, n);
theStr[0] = n;
cp = RFC822_QuoteStrCpy(cp, theStr);
paramHdl = (**paramHdl).next;
}
HUnlock(hStr);
SetHandleSize(hStr, GetHandleSize(hStr) - 1); // remove trailing null
Exit:
HUnlock((Handle) mimeH);
return hStr; // Return the header line
}
/* =========================================================================
* Convenient MIME type matcher - saves locking some handles
* If either type or subtype is nil, then it won't be checked.
* values and so on.
*
* Args: mimeH -- The mime type to check
* mType -- The major MIME type to check
* subtype -- The MIME subtype to check
*
* Returns: 1 if the MIME type matches, 0 if not
*/
short MatchMimeType(emsMIMEtypeH mimeH, const StringPtr mType, const StringPtr subtype)
{
Str63 theStr;
short result = 1;
if (mType != nil) {
CopyPP((**mimeH).mimeType, theStr);
result = EqualString(theStr, mType, false, true);
}
if (result && subtype != nil) {
CopyPP((**mimeH).subType, theStr);
result = EqualString(theStr, subtype, false, true);
}
return result;
}
#pragma mark -
/* =========================================================================
* Add a parameter to a MIME type
*
* Might have to make the value parameter a Handle instead of a StringPtr
* to accomodate items longer than 255 characters
*
* Args: mimeH -- Handle for the MIME type to add too
* mType -- Name of the parameter (Pascal string)
* subtype -- Value of the parameter (currently a Pascal string)
*/
void AddMimeParameter(emsMIMEtypeH mimeH, const StringPtr name, const StringPtr value)
{
emsMIMEparam param;
emsMIMEparamH ph, endPH;
endPH = nil; // Find last handle in the param list
for (ph = (**mimeH).params; ph != nil; ph = (**ph).next) {
endPH = ph;
}
param.size = sizeof(emsMIMEparam);
CopyPP(name, param.name);
param.value = nil;
PtrToHand(value + 1, ¶m.value, value[0]);
param.next = nil;
ph = nil;
PtrToHand(¶m, (Handle*) &ph, sizeof(emsMIMEparam));
if (endPH == nil) // It's an empty list
(**mimeH).params = ph;
else // Put at end of list
(**endPH).next = ph;
}
/* =========================================================================
* Pick out a specific parameter from a MIME type
*
* Args: mimeH -- Handle to a struct ems_MIME_type
* paramName -- string with name of parameter to look for
*
* Returns: handle to string which is the value or nil (It is not a pascal string)
*/
Handle GetMimeParameter(emsMIMEtypeH mimeH, const StringPtr paramName)
{
long result;
Str63 theStr;
emsMIMEparam **ph;
for (ph = (**mimeH).params; ph != nil; ph = (**ph).next) {
CopyPP((**ph).name, theStr);
result = EqualString(theStr, paramName, false, true);
if (result)
return (**ph).value;
}
return nil;
}
/* =========================================================================
* Remove a parameter from an existing emsMIMEtype structure. This structure
* should be created using MakeMimeType().
*
* NOTE: All input strings are COPIED before permanent use.
*
* Args: mimeH [IN] Handle to the emsMIMEtype structure to altered
* name [IN] Name of the parameter to be removed
*
* Returns: Boolean (true = success, false = failure)
*/
Boolean RemoveMimeParameter(emsMIMEtypeH mimeH, const StringPtr name)
{
emsMIMEparamH paramH, prevParamH;
Str63 theStr;
if (!mimeH)
return false;
paramH = (**mimeH).params;
prevParamH = nil;
while (paramH != nil) { /* Find the parameter */
CopyPP((**paramH).name, theStr);
if (EqualString(theStr, name, false, true))
break;
prevParamH = paramH;
paramH = (**paramH).next;
}
if (paramH == nil)
return false; /* Not found */
if (prevParamH == nil) /* Removing first in list */
(**mimeH).params = (**paramH).next;
else
(**prevParamH).next = (**paramH).next;
DisposeHandle((**paramH).value);
DisposeHandle((Handle) paramH);
return true;
}
/* =========================================================================
* Private function used to free the parameter linked-list
*
* Args: mimeH Handle to the parameter to be removed
*/
void FreeParamType(emsMIMEparamH paramH)
{
emsMIMEparamH nextParamH;
while (paramH) {
nextParamH = (**paramH).next;
if ((**paramH).value != nil)
DisposeHandle((**paramH).value);
DisposeHandle((Handle) paramH);
paramH = nextParamH;
}
}